package com.tang.netty.nio.network;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

import static com.tang.netty.nio.buffer.ByteBufferUtil.debugRead;

/**
 * 使用nio来理解阻塞模式
 *
 * @author tang
 * @since 2023/7/23 20:11
 */
@Slf4j
public class NonBlockServer {

    public static void main(String[] args) throws IOException {
        // 这里故意使用了单线程连接
        // 0. 设置一个全局的ByteBuffer，测试嘛，不发送太多数据，也没有线程。
        ByteBuffer byteBuffer = ByteBuffer.allocate(16);
        // 1. 创建Server
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            serverSocketChannel.configureBlocking(false); // 非阻塞模式
            // 2. 绑定监听端口，服务端采用此端口与客户端建立连接
            serverSocketChannel.bind(new InetSocketAddress(8080));
            // 3. 连接集合
            List<SocketChannel> channelList = new ArrayList<>();
            while (true) { // 我们希望服务端可以连接多个客户端，所以加个while true, 不断的接收连接
                // 4. accept，服务端发起连接请求，如果客户端也发起请求，会通过TCP的三次握手把连接建立起来
                // 非阻塞，线程还会继续运行，如果没有建立连接，但sc是null
                SocketChannel socketChannel = serverSocketChannel.accept();
                if (null != socketChannel) {
                    log.debug("connected......{}", socketChannel);
                    // 非阻塞，那么调用read方法的时候，就也是非阻塞的了。
                    socketChannel.configureBlocking(false);
                    // 返回的socketChannel用来与客户端之间通信。存入第三步建立的List
                    channelList.add(socketChannel);
                }
                for (SocketChannel channel : channelList) {
                    // 5. 接收客户端发送的数据，存到byteBuffer里面
                    // 非阻塞，线程仍然会继续运行，如果没有读到数据，read返回0
                    int read = channel.read(byteBuffer);
                    if (read > 0) {
                        byteBuffer.flip();
                        debugRead(byteBuffer);
                        byteBuffer.clear();
                        log.debug("after read......{}", channel);
                    }
                }
            }
        }
    }

}
